/**
 * 
 */
package energySource;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import akka.stm.Atomic;
import akka.stm.Ref;

/**
 * @author mfan
 *
 */
public class EnergySource {
	private final long MAXLEVEL = 100;
	private final Ref<Long> level = new Ref<>(MAXLEVEL);
	private final Ref<Long> usageCount = new Ref<>(0L);
	private final Ref<Boolean> keepRunning = new Ref<>(true);
	
	private final ScheduledExecutorService replenishTimer = 
			Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
	
	private EnergySource() {
	}
	
	private void init() {
		replenishTimer.schedule(new Runnable() {
			
			@Override
			public void run() {
				replenish();
				
				if (keepRunning.get()) {
					replenishTimer.schedule(this, 1, TimeUnit.SECONDS);
				}
			}
		}, 1, TimeUnit.SECONDS);
	}
	
	public static EnergySource create() {
		final EnergySource energySource = new EnergySource();
		energySource.init();
		return energySource;
	}

	private void replenish() {
		new Atomic<Object>() {

			@Override
			public Object atomically() {
				// TODO Auto-generated method stub
				long currentlLevel = level.get();
				if (currentlLevel < MAXLEVEL) {
					level.swap(currentlLevel + 1);
				}
				return null;
			}
		}.execute();
	}
	
	public long getUnitsAvailable() {
		return level.get();
	}
	
	public long getUsageCount() {
		return usageCount.get();
	}
	
	public boolean useEnergy(final long units) {
		return new Atomic<Boolean>() {

			@Override
			public Boolean atomically() {
				long currentLevel = level.get();
				if (units > 0 && currentLevel >= units) {
					level.swap(currentLevel - units);
					usageCount.swap(usageCount.get() + 1);
					return true;
				} else {
					return false;
				}
			}
		}.execute();
	}
	
	public void stopEnergySource() {
		keepRunning.swap(false);
	}

}
